{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# The Qmod Workshop - Part 2: Higher-Level Concepts\n",
    "\n",
    "This is the second part of the Qmod workshop, covering exercises 6 through 10. Make sure to go through Part 1 before continuing with this notebook."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from classiq import *"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 6 - Exponentiation and Pauli Operators\n",
    "\n",
    "The Qmod language supports different classical types: scalars, arrays, and structs. Structs are objects with member variables, or fields.\n",
    "\n",
    "See also [Classical Types](https://docs.classiq.io/latest/user-guide/platform/qmod/language-reference/classical-types/#structs).\n",
    "\n",
    "The builtin struct type `PauliTerm` is defined as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "@struct\n",
    "class PauliTerm:\n",
    "    pauli: CArray[Pauli]\n",
    "    coefficient: CReal"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that `Pauli` is an enum for all the Pauli matrices (I, X, Y, Z).\n",
    "\n",
    "Pauli based hamiltonian can be represented as a list of `PauliTerm`s. A Pauli operator defined this way is the argument to a hamiltonian evolution functions.\n",
    "\n",
    "In this exercise we will use the Suzuki-Trotter function to find the evolution of `H=0.5XZXX + 0.25YIZI + 0.3 XIZY` (captured as a literal value for the pauli-operator), with the evolution coefficient being 3, the order being 2, and use 4 repetitions.\n",
    "\n",
    "The declaration of the `suzuki_trotter` function is:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "@qfunc(external=True)\n",
    "def suzuki_trotter(\n",
    "    pauli_operator: CArray[PauliTerm],\n",
    "    evolution_coefficient: CReal,\n",
    "    order: CInt,\n",
    "    repetitions: CInt,\n",
    "    qbv: QArray[QBit],\n",
    ") -> None:\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Fill in the missing parts of the following code in order to complete this exercise:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "ename": "PasswordSetError",
     "evalue": "Can't store password on keychain: (-25244, 'Unknown Error')",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mClassiqExpiredTokenError\u001b[0m                  Traceback (most recent call last)",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/_internals/client.py:114\u001b[0m, in \u001b[0;36mtry_again_on_failure.<locals>.wrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m    113\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 114\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m func(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[1;32m    115\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m ClassiqExpiredTokenError:\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/_internals/jobs.py:103\u001b[0m, in \u001b[0;36mJobPoller._request\u001b[0;34m(self, http_method, url, body)\u001b[0m\n\u001b[1;32m    100\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_async_client\u001b[38;5;241m.\u001b[39mrequest(\n\u001b[1;32m    101\u001b[0m     method\u001b[38;5;241m=\u001b[39mhttp_method, url\u001b[38;5;241m=\u001b[39murl, json\u001b[38;5;241m=\u001b[39mbody, headers\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_additional_headers\n\u001b[1;32m    102\u001b[0m )\n\u001b[0;32m--> 103\u001b[0m \u001b[43mclient\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mhandle_response\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    104\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m response\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/_internals/client.py:190\u001b[0m, in \u001b[0;36mClient.handle_response\u001b[0;34m(self, response)\u001b[0m\n\u001b[1;32m    189\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m response\u001b[38;5;241m.\u001b[39mis_error:\n\u001b[0;32m--> 190\u001b[0m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_handle_error\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    191\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_handle_success(response)\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/_internals/client.py:201\u001b[0m, in \u001b[0;36mClient._handle_error\u001b[0;34m(response)\u001b[0m\n\u001b[1;32m    200\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m expired:\n\u001b[0;32m--> 201\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m ClassiqExpiredTokenError(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mExpired token\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m    203\u001b[0m message \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCall to API failed with code \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mresponse\u001b[38;5;241m.\u001b[39mstatus_code\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n",
      "\u001b[0;31mClassiqExpiredTokenError\u001b[0m: Expired token\nIf you need further assistance, please reach out on our Community Slack channel at: https://short.classiq.io/join-slack\nIf the error persists feel free to open a ticket at: https://short.classiq.io/support",
      "\nDuring handling of the above exception, another exception occurred:\n",
      "\u001b[0;31mError\u001b[0m                                     Traceback (most recent call last)",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/keyring/backends/macOS/__init__.py:40\u001b[0m, in \u001b[0;36mKeyring.set_password\u001b[0;34m(self, service, username, password)\u001b[0m\n\u001b[1;32m     39\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 40\u001b[0m     \u001b[43mapi\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_generic_password\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mkeychain\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mservice\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43musername\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpassword\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     41\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m api\u001b[38;5;241m.\u001b[39mKeychainDenied \u001b[38;5;28;01mas\u001b[39;00m e:\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/keyring/backends/macOS/api.py:152\u001b[0m, in \u001b[0;36mset_generic_password\u001b[0;34m(name, service, username, password)\u001b[0m\n\u001b[1;32m    151\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m contextlib\u001b[38;5;241m.\u001b[39msuppress(NotFound):\n\u001b[0;32m--> 152\u001b[0m     \u001b[43mdelete_generic_password\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mservice\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43musername\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    154\u001b[0m q \u001b[38;5;241m=\u001b[39m create_query(\n\u001b[1;32m    155\u001b[0m     kSecClass\u001b[38;5;241m=\u001b[39mk_(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mkSecClassGenericPassword\u001b[39m\u001b[38;5;124m'\u001b[39m),\n\u001b[1;32m    156\u001b[0m     kSecAttrService\u001b[38;5;241m=\u001b[39mservice,\n\u001b[1;32m    157\u001b[0m     kSecAttrAccount\u001b[38;5;241m=\u001b[39musername,\n\u001b[1;32m    158\u001b[0m     kSecValueData\u001b[38;5;241m=\u001b[39mpassword,\n\u001b[1;32m    159\u001b[0m )\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/keyring/backends/macOS/api.py:173\u001b[0m, in \u001b[0;36mdelete_generic_password\u001b[0;34m(name, service, username)\u001b[0m\n\u001b[1;32m    172\u001b[0m status \u001b[38;5;241m=\u001b[39m SecItemDelete(q)\n\u001b[0;32m--> 173\u001b[0m \u001b[43mError\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mraise_for_status\u001b[49m\u001b[43m(\u001b[49m\u001b[43mstatus\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/keyring/backends/macOS/api.py:115\u001b[0m, in \u001b[0;36mError.raise_for_status\u001b[0;34m(cls, status)\u001b[0m\n\u001b[1;32m    110\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m SecAuthFailure(\n\u001b[1;32m    111\u001b[0m         status,\n\u001b[1;32m    112\u001b[0m         \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mSecurity Auth Failure: make sure \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m    113\u001b[0m         \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpython is signed with codesign util\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m    114\u001b[0m     )\n\u001b[0;32m--> 115\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;28mcls\u001b[39m(status, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mUnknown Error\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n",
      "\u001b[0;31mError\u001b[0m: (-25244, 'Unknown Error')",
      "\nDuring handling of the above exception, another exception occurred:\n",
      "\u001b[0;31mPasswordSetError\u001b[0m                          Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[4], line 21\u001b[0m\n\u001b[1;32m      7\u001b[0m     suzuki_trotter(\n\u001b[1;32m      8\u001b[0m         [\n\u001b[1;32m      9\u001b[0m         PauliTerm(pauli\u001b[38;5;241m=\u001b[39m[Pauli\u001b[38;5;241m.\u001b[39mX, Pauli\u001b[38;5;241m.\u001b[39mZ, Pauli\u001b[38;5;241m.\u001b[39mX, Pauli\u001b[38;5;241m.\u001b[39mX], coefficient\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m.5\u001b[39m),\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m     16\u001b[0m         qbv\u001b[38;5;241m=\u001b[39mq,\n\u001b[1;32m     17\u001b[0m     )\n\u001b[1;32m     20\u001b[0m qmod \u001b[38;5;241m=\u001b[39m create_model(main)\n\u001b[0;32m---> 21\u001b[0m qprog \u001b[38;5;241m=\u001b[39m \u001b[43msynthesize\u001b[49m\u001b[43m(\u001b[49m\u001b[43mqmod\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     22\u001b[0m show(qprog)\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/_internals/async_utils.py:45\u001b[0m, in \u001b[0;36msyncify_function.<locals>.async_wrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m     43\u001b[0m \u001b[38;5;129m@functools\u001b[39m\u001b[38;5;241m.\u001b[39mwraps(async_func)\n\u001b[1;32m     44\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21masync_wrapper\u001b[39m(\u001b[38;5;241m*\u001b[39margs: Any, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m T:\n\u001b[0;32m---> 45\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\u001b[43masync_func\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/_internals/async_utils.py:39\u001b[0m, in \u001b[0;36mrun\u001b[0;34m(coro)\u001b[0m\n\u001b[1;32m     34\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mrun\u001b[39m(coro: Awaitable[T]) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m T:\n\u001b[1;32m     35\u001b[0m     \u001b[38;5;66;03m# Use this function instead of asyncio.run, since it ALWAYS\u001b[39;00m\n\u001b[1;32m     36\u001b[0m     \u001b[38;5;66;03m# creates a new event loop and clears the thread event loop.\u001b[39;00m\n\u001b[1;32m     37\u001b[0m     \u001b[38;5;66;03m# Never use asyncio.run in library code.\u001b[39;00m\n\u001b[1;32m     38\u001b[0m     loop \u001b[38;5;241m=\u001b[39m get_event_loop()\n\u001b[0;32m---> 39\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mloop\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_until_complete\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcoro\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/nest_asyncio.py:90\u001b[0m, in \u001b[0;36m_patch_loop.<locals>.run_until_complete\u001b[0;34m(self, future)\u001b[0m\n\u001b[1;32m     87\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m f\u001b[38;5;241m.\u001b[39mdone():\n\u001b[1;32m     88\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\n\u001b[1;32m     89\u001b[0m         \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mEvent loop stopped before Future completed.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m---> 90\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mf\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mresult\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/asyncio/futures.py:201\u001b[0m, in \u001b[0;36mFuture.result\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    199\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__log_traceback \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mFalse\u001b[39;00m\n\u001b[1;32m    200\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_exception \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m--> 201\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_exception\n\u001b[1;32m    202\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_result\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/asyncio/tasks.py:256\u001b[0m, in \u001b[0;36mTask.__step\u001b[0;34m(***failed resolving arguments***)\u001b[0m\n\u001b[1;32m    252\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m    253\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m exc \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m    254\u001b[0m         \u001b[38;5;66;03m# We use the `send` method directly, because coroutines\u001b[39;00m\n\u001b[1;32m    255\u001b[0m         \u001b[38;5;66;03m# don't have `__iter__` and `__next__` methods.\u001b[39;00m\n\u001b[0;32m--> 256\u001b[0m         result \u001b[38;5;241m=\u001b[39m \u001b[43mcoro\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msend\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m)\u001b[49m\n\u001b[1;32m    257\u001b[0m     \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m    258\u001b[0m         result \u001b[38;5;241m=\u001b[39m coro\u001b[38;5;241m.\u001b[39mthrow(exc)\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/synthesis.py:20\u001b[0m, in \u001b[0;36msynthesize_async\u001b[0;34m(serialized_model)\u001b[0m\n\u001b[1;32m     16\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21msynthesize_async\u001b[39m(\n\u001b[1;32m     17\u001b[0m     serialized_model: SerializedModel,\n\u001b[1;32m     18\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m SerializedQuantumProgram:\n\u001b[1;32m     19\u001b[0m     model \u001b[38;5;241m=\u001b[39m pydantic\u001b[38;5;241m.\u001b[39mparse_raw_as(Model, serialized_model)\n\u001b[0;32m---> 20\u001b[0m     quantum_program \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m ApiWrapper\u001b[38;5;241m.\u001b[39mcall_generation_task(model)\n\u001b[1;32m     21\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m SerializedQuantumProgram(quantum_program\u001b[38;5;241m.\u001b[39mjson(indent\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m2\u001b[39m))\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/_internals/api_wrapper.py:107\u001b[0m, in \u001b[0;36mApiWrapper.call_generation_task\u001b[0;34m(cls, model)\u001b[0m\n\u001b[1;32m    102\u001b[0m \u001b[38;5;129m@classmethod\u001b[39m\n\u001b[1;32m    103\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mcall_generation_task\u001b[39m(\n\u001b[1;32m    104\u001b[0m     \u001b[38;5;28mcls\u001b[39m, model: Model\n\u001b[1;32m    105\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m generator_result\u001b[38;5;241m.\u001b[39mQuantumProgram:\n\u001b[1;32m    106\u001b[0m     poller \u001b[38;5;241m=\u001b[39m JobPoller(base_url\u001b[38;5;241m=\u001b[39mroutes\u001b[38;5;241m.\u001b[39mTASKS_GENERATE_FULL_PATH)\n\u001b[0;32m--> 107\u001b[0m     result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m poller\u001b[38;5;241m.\u001b[39mrun_pydantic(model, timeout_sec\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m)\n\u001b[1;32m    108\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m _parse_job_response(result, generator_result\u001b[38;5;241m.\u001b[39mQuantumProgram)\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/_internals/jobs.py:180\u001b[0m, in \u001b[0;36mJobPoller.run_pydantic\u001b[0;34m(self, model, timeout_sec)\u001b[0m\n\u001b[1;32m    173\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mrun_pydantic\u001b[39m(\n\u001b[1;32m    174\u001b[0m     \u001b[38;5;28mself\u001b[39m, model: pydantic\u001b[38;5;241m.\u001b[39mBaseModel, timeout_sec: Optional[\u001b[38;5;28mfloat\u001b[39m]\n\u001b[1;32m    175\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m GeneralJobDescription:\n\u001b[1;32m    176\u001b[0m     \u001b[38;5;66;03m# TODO: we can't use model.dict() - it doesn't serialize complex class.\u001b[39;00m\n\u001b[1;32m    177\u001b[0m     \u001b[38;5;66;03m# This was added because JSON serializer doesn't serialize complex type, and pydantic does.\u001b[39;00m\n\u001b[1;32m    178\u001b[0m     \u001b[38;5;66;03m# We should add support for smarter json serialization.\u001b[39;00m\n\u001b[1;32m    179\u001b[0m     body \u001b[38;5;241m=\u001b[39m json\u001b[38;5;241m.\u001b[39mloads(model\u001b[38;5;241m.\u001b[39mjson())\n\u001b[0;32m--> 180\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mrun(body, timeout_sec)\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/_internals/jobs.py:163\u001b[0m, in \u001b[0;36mJobPoller.run\u001b[0;34m(self, body, timeout_sec)\u001b[0m\n\u001b[1;32m    159\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mrun\u001b[39m(\n\u001b[1;32m    160\u001b[0m     \u001b[38;5;28mself\u001b[39m, body: Dict, timeout_sec: Optional[\u001b[38;5;28mfloat\u001b[39m]\n\u001b[1;32m    161\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m GeneralJobDescription:\n\u001b[1;32m    162\u001b[0m     \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_async_client:\n\u001b[0;32m--> 163\u001b[0m         submit_response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_submit(body\u001b[38;5;241m=\u001b[39mbody)\n\u001b[1;32m    164\u001b[0m         job_id \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_parse_job_id_response(response\u001b[38;5;241m=\u001b[39msubmit_response)\n\u001b[1;32m    165\u001b[0m         poll_url \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_make_poll_url(job_id\u001b[38;5;241m=\u001b[39mjob_id)\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/_internals/jobs.py:107\u001b[0m, in \u001b[0;36mJobPoller._submit\u001b[0;34m(self, body)\u001b[0m\n\u001b[1;32m    106\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_submit\u001b[39m(\u001b[38;5;28mself\u001b[39m, body: Dict) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m httpx\u001b[38;5;241m.\u001b[39mResponse:\n\u001b[0;32m--> 107\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_request(http_method\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mPOST\u001b[39m\u001b[38;5;124m\"\u001b[39m, url\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_base_url, body\u001b[38;5;241m=\u001b[39mbody)\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/_internals/client.py:125\u001b[0m, in \u001b[0;36mtry_again_on_failure.<locals>.wrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m    123\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m i \u001b[38;5;241m==\u001b[39m _RETRY_COUNT \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[1;32m    124\u001b[0m         \u001b[38;5;28;01mraise\u001b[39;00m\n\u001b[0;32m--> 125\u001b[0m     \u001b[38;5;28;01mawait\u001b[39;00m client()\u001b[38;5;241m.\u001b[39mupdate_expired_access_token()\n\u001b[1;32m    126\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m httpx\u001b[38;5;241m.\u001b[39mRemoteProtocolError:\n\u001b[1;32m    127\u001b[0m     _logger\u001b[38;5;241m.\u001b[39minfo(\n\u001b[1;32m    128\u001b[0m         \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mExperienced a httpx connection error, retrying to connect...\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m    129\u001b[0m     )\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/_internals/client.py:272\u001b[0m, in \u001b[0;36mClient.update_expired_access_token\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    271\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mupdate_expired_access_token\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m--> 272\u001b[0m     \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_token_manager\u001b[38;5;241m.\u001b[39mupdate_expired_access_token()\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/_internals/authentication/token_manager.py:75\u001b[0m, in \u001b[0;36mTokenManager.update_expired_access_token\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m     73\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mupdate_expired_access_token\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m     74\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_refresh_token \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m---> 75\u001b[0m         \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_refresh()\n\u001b[1;32m     76\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m\n\u001b[1;32m     77\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_clear_tokens()\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/_internals/authentication/token_manager.py:71\u001b[0m, in \u001b[0;36mTokenManager._refresh\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m     69\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_refresh_token \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m     70\u001b[0m tokens \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m Auth0()\u001b[38;5;241m.\u001b[39mrefresh_access_token(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_refresh_token)\n\u001b[0;32m---> 71\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_save_tokens\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtokens\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/_internals/authentication/token_manager.py:110\u001b[0m, in \u001b[0;36mTokenManager._save_tokens\u001b[0;34m(self, tokens, force_override_refresh_token)\u001b[0m\n\u001b[1;32m    108\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_lock:\n\u001b[1;32m    109\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_access_token \u001b[38;5;241m=\u001b[39m tokens\u001b[38;5;241m.\u001b[39maccess_token\n\u001b[0;32m--> 110\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_password_manager\u001b[38;5;241m.\u001b[39maccess_token \u001b[38;5;241m=\u001b[39m tokens\u001b[38;5;241m.\u001b[39maccess_token\n\u001b[1;32m    111\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m tokens\u001b[38;5;241m.\u001b[39mrefresh_token \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mor\u001b[39;00m force_override_refresh_token:\n\u001b[1;32m    112\u001b[0m         \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_refresh_token \u001b[38;5;241m=\u001b[39m tokens\u001b[38;5;241m.\u001b[39mrefresh_token\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/_internals/authentication/password_manager.py:38\u001b[0m, in \u001b[0;36mPasswordManager.access_token\u001b[0;34m(self, access_token)\u001b[0m\n\u001b[1;32m     36\u001b[0m \u001b[38;5;129m@access_token\u001b[39m\u001b[38;5;241m.\u001b[39msetter\n\u001b[1;32m     37\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21maccess_token\u001b[39m(\u001b[38;5;28mself\u001b[39m, access_token: Optional[\u001b[38;5;28mstr\u001b[39m]) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m---> 38\u001b[0m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_set\u001b[49m\u001b[43m(\u001b[49m\u001b[43mkey\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_settings\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mACCESS_TOKEN_KEY\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43maccess_token\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/_internals/authentication/password_manager.py:74\u001b[0m, in \u001b[0;36mKeyringPasswordManager._set\u001b[0;34m(self, key, value)\u001b[0m\n\u001b[1;32m     72\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_clear(key)\n\u001b[1;32m     73\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m\n\u001b[0;32m---> 74\u001b[0m \u001b[43mkeyring\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_password\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m     75\u001b[0m \u001b[43m    \u001b[49m\u001b[43mservice_name\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_SERVICE_NAME\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m     76\u001b[0m \u001b[43m    \u001b[49m\u001b[43musername\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mkey\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m     77\u001b[0m \u001b[43m    \u001b[49m\u001b[43mpassword\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mvalue\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m     78\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/keyring/core.py:60\u001b[0m, in \u001b[0;36mset_password\u001b[0;34m(service_name, username, password)\u001b[0m\n\u001b[1;32m     58\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mset_password\u001b[39m(service_name: \u001b[38;5;28mstr\u001b[39m, username: \u001b[38;5;28mstr\u001b[39m, password: \u001b[38;5;28mstr\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m     59\u001b[0m \u001b[38;5;250m    \u001b[39m\u001b[38;5;124;03m\"\"\"Set password for the user in the specified service.\"\"\"\u001b[39;00m\n\u001b[0;32m---> 60\u001b[0m     \u001b[43mget_keyring\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_password\u001b[49m\u001b[43m(\u001b[49m\u001b[43mservice_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43musername\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpassword\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/keyring/backends/macOS/__init__.py:44\u001b[0m, in \u001b[0;36mKeyring.set_password\u001b[0;34m(self, service, username, password)\u001b[0m\n\u001b[1;32m     42\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m KeyringLocked(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCan\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mt store password on keychain: \u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;241m.\u001b[39mformat(e))\n\u001b[1;32m     43\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m api\u001b[38;5;241m.\u001b[39mError \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[0;32m---> 44\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m PasswordSetError(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCan\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mt store password on keychain: \u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;241m.\u001b[39mformat(e))\n",
      "\u001b[0;31mPasswordSetError\u001b[0m: Can't store password on keychain: (-25244, 'Unknown Error')"
     ]
    }
   ],
   "source": [
    "from classiq import *\n",
    "\n",
    "\n",
    "@qfunc\n",
    "def main(q: Output[QArray[QBit]]) -> None:\n",
    "    allocate(4, q)\n",
    "    suzuki_trotter(\n",
    "        [\n",
    "        PauliTerm(pauli=[Pauli.X, Pauli.Z, Pauli.X, Pauli.X], coefficient=.5),\n",
    "        PauliTerm(pauli=[Pauli.Y, Pauli.I, Pauli.Z, Pauli.I], coefficient=.25),\n",
    "        PauliTerm(pauli=[Pauli.X, Pauli.I, Pauli.Z, Pauli.Y], coefficient=.3)\n",
    "        ],\n",
    "        evolution_coefficient=3,\n",
    "        repetitions=4,\n",
    "        order=2,\n",
    "        qbv=q,\n",
    "    )\n",
    "\n",
    "\n",
    "qmod = create_model(main)\n",
    "qprog = synthesize(qmod)\n",
    "show(qprog)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 7 - Basic Arithmetics\n",
    "\n",
    "#### Exercise 7a\n",
    "In this exercise we will use quantum numeric variables and calculate expressions over them.\n",
    "\n",
    "See details on the syntax of numeric types under [Quantum types](https://docs.classiq.io/latest/user-guide/platform/qmod/language-reference/quantum-types/#syntax).\n",
    "See more on quantum expressions under [Numeric assignment](https://docs.classiq.io/latest/user-guide/platform/qmod/language-reference/statements/numeric-assignment/)\n",
    "\n",
    "Create the following quantum programs:\n",
    "1. Initialize variables `x=2`, `y=7` and computes `res = x + y`.\n",
    "2. Initialize variables `x=2`, `y=7` and computes `res = x * y`.\n",
    "3. Initialize variables `x=2`, `y=7`, `z=1` and computes `res = x * y - z`.\n",
    "\n",
    "Guidance:\n",
    "* Use the operator `|=` to perform out-of-place assignment of arithmetic expression.\n",
    "* To initialize the variables, use the function `prepare_int`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from classiq import *\n",
    "\n",
    "@qfunc\n",
    "def main(res: Output[QNum]):\n",
    "    x = QNum(\"x\")\n",
    "    y = QNum(\"y\")\n",
    "    prepare_int(2,x)\n",
    "    prepare_int(7,y)\n",
    "    res |= x + y\n",
    "\n",
    "\n",
    "qmod = create_model(main)\n",
    "qprog = synthesize(qmod)\n",
    "show(qprog)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from classiq import *\n",
    "\n",
    "@qfunc\n",
    "def main(res: Output[QNum]):\n",
    "    x = QNum(\"x\")\n",
    "    y = QNum(\"y\")\n",
    "    prepare_int(2,x)\n",
    "    prepare_int(7,y)\n",
    "    res |= x * y \n",
    "\n",
    "\n",
    "qmod = create_model(main)\n",
    "qprog = synthesize(qmod)\n",
    "show(qprog)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from classiq import *\n",
    "\n",
    "@qfunc\n",
    "def main(res: Output[QNum]):\n",
    "    x = QNum(\"x\")\n",
    "    y = QNum(\"y\")\n",
    "    z = QNum(\"z\")\n",
    "    prepare_int(2,x)\n",
    "    prepare_int(7,y)\n",
    "    prepare_int(1,z)\n",
    "    res |= x * y -z\n",
    "\n",
    "\n",
    "qmod = create_model(main)\n",
    "qprog = synthesize(qmod)\n",
    "show(qprog)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Exercise 7b\n",
    "Declare `x` to be a 2-qubit variable and `y` to be 3-qubit variable.\n",
    "\n",
    "We will perform an addition of two superposition states: `x` is an equal superposition of `0` and `2`, and `y` is an equal superposition of `1`, `2`, `3`, and `6`.\n",
    "\n",
    "1. Use `prepare_state` to initialize `x` and `y`. Note that `prepare_state` works with probabilities, not amplitudes.\n",
    "   The declaration of the `prepare_state` function is:\n",
    "   ```\n",
    "        @qfunc(external=True)\n",
    "        def prepare_state(\n",
    "            probabilities: CArray[CReal],\n",
    "            bound: CReal,\n",
    "            out: Output[QArray[QBit]],\n",
    "        ) -> None:\n",
    "            pass\n",
    "   ```\n",
    "   (Set the bound to 0 in your code)\n",
    "2. Compute `res = x + y`. Execute the resulting circuit. What did you get?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@qfunc\n",
    "def main(res: Output[QNum]) -> None:\n",
    "    x = QNum(\"x\")\n",
    "    y = QNum(\"y\")\n",
    "    #allocate(2,x)\n",
    "    #allocate(3,y)\n",
    "    \n",
    "    prepare_state(probabilities=[0,1/4,1/4,1/4,0,0,1/4,0], bound=0, out=y)\n",
    "    prepare_state(probabilities=[1/2,0,1/2,0,0,0,0,0], bound=0, out=x)\n",
    "    \n",
    "    res|=x+y\n",
    "\n",
    "qmod = create_model(main)\n",
    "qprog = synthesize(qmod)\n",
    "show(qprog)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 8 - Within-Apply\n",
    "\n",
    "The within-apply statement applies the pattern `U_dagger V U` that appears frequently in quantum computing.\n",
    "It allows you to compute some function `V` within the context of another function `U`, and afterward uncompute `U` in order to release auxiliary qubits storing intermediate results.\n",
    "\n",
    "See also [Within Apply](https://docs.classiq.io/latest/user-guide/platform/qmod/language-reference/statements/within-apply/).\n",
    "\n",
    "#### Exercise 8a\n",
    "\n",
    "In this exercise, we will use within-apply to compute an arithmetic expression in steps.\n",
    "\n",
    "Use the `within_apply` operation to calculate `res = x + y + z` from a two-variable addition building block with the following steps:\n",
    "1. Add `x` and `y`\n",
    "2. Add the result to `z`\n",
    "3. Uncompute the result of the first operation\n",
    "\n",
    "For simplicity, initialize the registers to simple integers: `x=3`, `y=5`, `z=2`.\n",
    "\n",
    "Hints:\n",
    "\n",
    "* Use a temporary variable.\n",
    "* Wrap the arithmetic operation in a function.\n",
    "\n",
    "Execute the circuit and make sure you obtain the expected result."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'int' object has no attribute 'get_handle_binding'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[11], line 22\u001b[0m\n\u001b[1;32m     19\u001b[0m     z\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m2\u001b[39m\n\u001b[1;32m     20\u001b[0m     within_apply(\u001b[38;5;28;01mlambda\u001b[39;00m: inplace_linear_attempt_a(x,y), \u001b[38;5;28;01mlambda\u001b[39;00m: linear_func_a(z,res))\n\u001b[0;32m---> 22\u001b[0m qmod \u001b[38;5;241m=\u001b[39m \u001b[43mcreate_model\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmain\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     23\u001b[0m qprog \u001b[38;5;241m=\u001b[39m synthesize(qmod)\n\u001b[1;32m     24\u001b[0m show(qprog)\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_function.py:43\u001b[0m, in \u001b[0;36mcreate_model\u001b[0;34m(entry_point, constraints, execution_preferences, preferences, classical_execution_function)\u001b[0m\n\u001b[1;32m     39\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m entry_point\u001b[38;5;241m.\u001b[39mfunc_decl\u001b[38;5;241m.\u001b[39mname \u001b[38;5;241m!=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmain\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m     40\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m ClassiqError(\n\u001b[1;32m     41\u001b[0m         \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThe entry point function must be named \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmain\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, got \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mentry_point\u001b[38;5;241m.\u001b[39mfunc_decl\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m     42\u001b[0m     )\n\u001b[0;32m---> 43\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mentry_point\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcreate_model\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m     44\u001b[0m \u001b[43m    \u001b[49m\u001b[43mconstraints\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mexecution_preferences\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpreferences\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mclassical_execution_function\u001b[49m\n\u001b[1;32m     45\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39mget_model()\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_function.py:78\u001b[0m, in \u001b[0;36mQFunc.create_model\u001b[0;34m(self, constraints, execution_preferences, preferences, classical_execution_function)\u001b[0m\n\u001b[1;32m     76\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_qmodule\u001b[38;5;241m.\u001b[39mconstants \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mdict\u001b[39m()\n\u001b[1;32m     77\u001b[0m QConstant\u001b[38;5;241m.\u001b[39mset_current_model(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_qmodule)\n\u001b[0;32m---> 78\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_add_native_func_def\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     79\u001b[0m model_extra_settings: List[Tuple[\u001b[38;5;28mstr\u001b[39m, Any]] \u001b[38;5;241m=\u001b[39m [\n\u001b[1;32m     80\u001b[0m     (\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mconstraints\u001b[39m\u001b[38;5;124m\"\u001b[39m, constraints),\n\u001b[1;32m     81\u001b[0m     (\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mexecution_preferences\u001b[39m\u001b[38;5;124m\"\u001b[39m, execution_preferences),\n\u001b[1;32m     82\u001b[0m     (\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpreferences\u001b[39m\u001b[38;5;124m\"\u001b[39m, preferences),\n\u001b[1;32m     83\u001b[0m ]\n\u001b[1;32m     84\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m classical_execution_function \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_function.py:99\u001b[0m, in \u001b[0;36mQFunc._add_native_func_def\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m     97\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfunc_decl\u001b[38;5;241m.\u001b[39mname \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_qmodule\u001b[38;5;241m.\u001b[39mnative_defs:\n\u001b[1;32m     98\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m\n\u001b[0;32m---> 99\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexpand\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    100\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_qmodule\u001b[38;5;241m.\u001b[39mnative_defs[\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfunc_decl\u001b[38;5;241m.\u001b[39mname] \u001b[38;5;241m=\u001b[39m NativeFunctionDefinition(\n\u001b[1;32m    101\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m{\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfunc_decl\u001b[38;5;241m.\u001b[39mdict(), \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m{\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mbody\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbody}}\n\u001b[1;32m    102\u001b[0m )\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_expandable.py:86\u001b[0m, in \u001b[0;36mQExpandable.expand\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m     84\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m QExpandable\u001b[38;5;241m.\u001b[39mSTACK:\n\u001b[1;32m     85\u001b[0m     \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m:\n\u001b[0;32m---> 86\u001b[0m         \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_py_callable\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_get_positional_args\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n",
      "Cell \u001b[0;32mIn[11], line 20\u001b[0m, in \u001b[0;36mmain\u001b[0;34m(temp, res)\u001b[0m\n\u001b[1;32m     18\u001b[0m y\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m5\u001b[39m\n\u001b[1;32m     19\u001b[0m z\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m2\u001b[39m\n\u001b[0;32m---> 20\u001b[0m \u001b[43mwithin_apply\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43;01mlambda\u001b[39;49;00m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43minplace_linear_attempt_a\u001b[49m\u001b[43m(\u001b[49m\u001b[43mx\u001b[49m\u001b[43m,\u001b[49m\u001b[43my\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mlambda\u001b[39;49;00m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mlinear_func_a\u001b[49m\u001b[43m(\u001b[49m\u001b[43mz\u001b[49m\u001b[43m,\u001b[49m\u001b[43mres\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/builtins/operations.py:149\u001b[0m, in \u001b[0;36mwithin_apply\u001b[0;34m(compute, action)\u001b[0m\n\u001b[1;32m    144\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m QCallable\u001b[38;5;241m.\u001b[39mCURRENT_EXPANDABLE \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m    145\u001b[0m source_ref \u001b[38;5;241m=\u001b[39m get_source_ref(sys\u001b[38;5;241m.\u001b[39m_getframe(\u001b[38;5;241m1\u001b[39m))\n\u001b[1;32m    146\u001b[0m QCallable\u001b[38;5;241m.\u001b[39mCURRENT_EXPANDABLE\u001b[38;5;241m.\u001b[39mappend_statement_to_body(\n\u001b[1;32m    147\u001b[0m     WithinApply(\n\u001b[1;32m    148\u001b[0m         compute\u001b[38;5;241m=\u001b[39m_operand_to_body(compute),\n\u001b[0;32m--> 149\u001b[0m         action\u001b[38;5;241m=\u001b[39m\u001b[43m_operand_to_body\u001b[49m\u001b[43m(\u001b[49m\u001b[43maction\u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m    150\u001b[0m         source_ref\u001b[38;5;241m=\u001b[39msource_ref,\n\u001b[1;32m    151\u001b[0m     )\n\u001b[1;32m    152\u001b[0m )\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/builtins/operations.py:254\u001b[0m, in \u001b[0;36m_operand_to_body\u001b[0;34m(callable_)\u001b[0m\n\u001b[1;32m    253\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_operand_to_body\u001b[39m(callable_: Union[QCallable, Callable[[], \u001b[38;5;28;01mNone\u001b[39;00m]]) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m StatementBlock:\n\u001b[0;32m--> 254\u001b[0m     to_operand \u001b[38;5;241m=\u001b[39m \u001b[43mprepare_arg\u001b[49m\u001b[43m(\u001b[49m\u001b[43mQuantumOperandDeclaration\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcallable_\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    255\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(to_operand, \u001b[38;5;28mstr\u001b[39m):\n\u001b[1;32m    256\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m [QuantumFunctionCall(function\u001b[38;5;241m=\u001b[39mto_operand)]\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_expandable.py:230\u001b[0m, in \u001b[0;36mprepare_arg\u001b[0;34m(arg_decl, val)\u001b[0m\n\u001b[1;32m    227\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(val, QExpandable):\n\u001b[1;32m    228\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m val\u001b[38;5;241m.\u001b[39mfunc_decl\u001b[38;5;241m.\u001b[39mname\n\u001b[0;32m--> 230\u001b[0m \u001b[43mval\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexpand\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    231\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m QuantumLambdaFunction(\n\u001b[1;32m    232\u001b[0m     rename_params\u001b[38;5;241m=\u001b[39mval\u001b[38;5;241m.\u001b[39minfer_rename_params(), body\u001b[38;5;241m=\u001b[39mval\u001b[38;5;241m.\u001b[39mbody\n\u001b[1;32m    233\u001b[0m )\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_expandable.py:86\u001b[0m, in \u001b[0;36mQExpandable.expand\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m     84\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m QExpandable\u001b[38;5;241m.\u001b[39mSTACK:\n\u001b[1;32m     85\u001b[0m     \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m:\n\u001b[0;32m---> 86\u001b[0m         \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_py_callable\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_get_positional_args\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n",
      "Cell \u001b[0;32mIn[11], line 20\u001b[0m, in \u001b[0;36mmain.<locals>.<lambda>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     18\u001b[0m y\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m5\u001b[39m\n\u001b[1;32m     19\u001b[0m z\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m2\u001b[39m\n\u001b[0;32m---> 20\u001b[0m within_apply(\u001b[38;5;28;01mlambda\u001b[39;00m: inplace_linear_attempt_a(x,y), \u001b[38;5;28;01mlambda\u001b[39;00m: \u001b[43mlinear_func_a\u001b[49m\u001b[43m(\u001b[49m\u001b[43mz\u001b[49m\u001b[43m,\u001b[49m\u001b[43mres\u001b[49m\u001b[43m)\u001b[49m)\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_function.py:64\u001b[0m, in \u001b[0;36mQFunc.__call__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m     63\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__call__\u001b[39m(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;241m*\u001b[39margs: Any, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m---> 64\u001b[0m     \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__call__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     65\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_add_native_func_def()\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_callable.py:50\u001b[0m, in \u001b[0;36mQCallable.__call__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m     47\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m QCallable\u001b[38;5;241m.\u001b[39mCURRENT_EXPANDABLE \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m     48\u001b[0m source_ref \u001b[38;5;241m=\u001b[39m get_source_ref(sys\u001b[38;5;241m.\u001b[39m_getframe(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mFRAME_DEPTH))\n\u001b[1;32m     49\u001b[0m QCallable\u001b[38;5;241m.\u001b[39mCURRENT_EXPANDABLE\u001b[38;5;241m.\u001b[39mappend_statement_to_body(\n\u001b[0;32m---> 50\u001b[0m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcreate_quantum_function_call\u001b[49m\u001b[43m(\u001b[49m\u001b[43msource_ref\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     51\u001b[0m )\n\u001b[1;32m     52\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_expandable.py:116\u001b[0m, in \u001b[0;36mQExpandable.create_quantum_function_call\u001b[0;34m(self, source_ref_, *args, **kwargs)\u001b[0m\n\u001b[1;32m    113\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mcreate_quantum_function_call\u001b[39m(\n\u001b[1;32m    114\u001b[0m     \u001b[38;5;28mself\u001b[39m, source_ref_: SourceReference, \u001b[38;5;241m*\u001b[39margs: Any, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any\n\u001b[1;32m    115\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m QuantumFunctionCall:\n\u001b[0;32m--> 116\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m_create_quantum_function_call\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    117\u001b[0m \u001b[43m        \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfunc_decl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msource_ref_\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\n\u001b[1;32m    118\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_expandable.py:292\u001b[0m, in \u001b[0;36m_create_quantum_function_call\u001b[0;34m(decl_, index_, source_ref_, *args, **kwargs)\u001b[0m\n\u001b[1;32m    290\u001b[0m arg_decls \u001b[38;5;241m=\u001b[39m decl_\u001b[38;5;241m.\u001b[39mget_positional_arg_decls()\n\u001b[1;32m    291\u001b[0m arg_list \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mlist\u001b[39m(args)\n\u001b[0;32m--> 292\u001b[0m prepared_args \u001b[38;5;241m=\u001b[39m \u001b[43m_prepare_args\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdecl_\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43marg_list\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    294\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m kwargs:\n\u001b[1;32m    295\u001b[0m     bad_kwarg \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mnext\u001b[39m(\u001b[38;5;28miter\u001b[39m(kwargs))\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_expandable.py:278\u001b[0m, in \u001b[0;36m_prepare_args\u001b[0;34m(decl, arg_list, kwargs)\u001b[0m\n\u001b[1;32m    276\u001b[0m             error_message \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m _get_operand_hint(decl, arg_decl)\n\u001b[1;32m    277\u001b[0m         \u001b[38;5;28;01mraise\u001b[39;00m ClassiqValueError(error_message)\n\u001b[0;32m--> 278\u001b[0m     result\u001b[38;5;241m.\u001b[39mappend(\u001b[43mprepare_arg\u001b[49m\u001b[43m(\u001b[49m\u001b[43marg_decl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43marg\u001b[49m\u001b[43m)\u001b[49m)\n\u001b[1;32m    280\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m result\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_expandable.py:214\u001b[0m, in \u001b[0;36mprepare_arg\u001b[0;34m(arg_decl, val)\u001b[0m\n\u001b[1;32m    212\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m Expression(expr\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mstr\u001b[39m(val))\n\u001b[1;32m    213\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(arg_decl, PortDeclaration):\n\u001b[0;32m--> 214\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mval\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_handle_binding\u001b[49m()\n\u001b[1;32m    215\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m    216\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(val, \u001b[38;5;28mlist\u001b[39m):\n",
      "\u001b[0;31mAttributeError\u001b[0m: 'int' object has no attribute 'get_handle_binding'"
     ]
    }
   ],
   "source": [
    "@qfunc\n",
    "def inplace_linear_attempt_a(x:CInt,y:CInt) -> None:\n",
    "    temp = QNum(\"tmp\")\n",
    "    temp |= x + y\n",
    "    \n",
    "    \n",
    "\n",
    "@qfunc\n",
    "def linear_func_a(temp: QNum, z: CInt, res: Output[QNum]):\n",
    "    res |= temp +z\n",
    "\n",
    "@qfunc\n",
    "def main(temp: Output[QNum],res: Output[QNum] ) -> None:\n",
    "    #x = QNum(\"x\")\n",
    "    #y = QNum(\"y\")\n",
    "    #z = QNum(\"z\")\n",
    "    x=3\n",
    "    y=5\n",
    "    z=2\n",
    "    within_apply(lambda: inplace_linear_attempt_a(x,y), lambda: linear_func_a(z,res))\n",
    "\n",
    "qmod = create_model(main)\n",
    "qprog = synthesize(qmod)\n",
    "show(qprog)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "ename": "ClassiqValueError",
     "evalue": "'linear_add_s1' is missing required argument for 'y'\nIf you need further assistance, please reach out on our Community Slack channel at: https://short.classiq.io/join-slack\nIf the error persists feel free to open a ticket at: https://short.classiq.io/support",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mClassiqValueError\u001b[0m                         Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[25], line 21\u001b[0m\n\u001b[1;32m     18\u001b[0m     within_apply(\u001b[38;5;28;01mlambda\u001b[39;00m: linear_add_s1(x,y,z), \u001b[38;5;28;01mlambda\u001b[39;00m: linear_add_s1(z))\n\u001b[1;32m     19\u001b[0m     \u001b[38;5;66;03m#within\u001b[39;00m\n\u001b[0;32m---> 21\u001b[0m qmod \u001b[38;5;241m=\u001b[39m \u001b[43mcreate_model\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmain\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     22\u001b[0m qprog \u001b[38;5;241m=\u001b[39m synthesize(qmod)\n\u001b[1;32m     23\u001b[0m show(qprog)\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_function.py:44\u001b[0m, in \u001b[0;36mcreate_model\u001b[0;34m(entry_point, constraints, execution_preferences, preferences, classical_execution_function)\u001b[0m\n\u001b[1;32m     40\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m entry_point\u001b[38;5;241m.\u001b[39mfunc_decl\u001b[38;5;241m.\u001b[39mname \u001b[38;5;241m!=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmain\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m     41\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m ClassiqError(\n\u001b[1;32m     42\u001b[0m         \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThe entry point function must be named \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmain\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, got \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mentry_point\u001b[38;5;241m.\u001b[39mfunc_decl\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m     43\u001b[0m     )\n\u001b[0;32m---> 44\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mentry_point\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcreate_model\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m     45\u001b[0m \u001b[43m    \u001b[49m\u001b[43mconstraints\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mexecution_preferences\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpreferences\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mclassical_execution_function\u001b[49m\n\u001b[1;32m     46\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39mget_model()\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_function.py:89\u001b[0m, in \u001b[0;36mQFunc.create_model\u001b[0;34m(self, constraints, execution_preferences, preferences, classical_execution_function)\u001b[0m\n\u001b[1;32m     87\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_qmodule\u001b[38;5;241m.\u001b[39mconstants \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mdict\u001b[39m()\n\u001b[1;32m     88\u001b[0m QConstant\u001b[38;5;241m.\u001b[39mset_current_model(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_qmodule)\n\u001b[0;32m---> 89\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_add_native_func_def\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     90\u001b[0m model_extra_settings: List[Tuple[\u001b[38;5;28mstr\u001b[39m, Any]] \u001b[38;5;241m=\u001b[39m [\n\u001b[1;32m     91\u001b[0m     (\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mconstraints\u001b[39m\u001b[38;5;124m\"\u001b[39m, constraints),\n\u001b[1;32m     92\u001b[0m     (\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mexecution_preferences\u001b[39m\u001b[38;5;124m\"\u001b[39m, execution_preferences),\n\u001b[1;32m     93\u001b[0m     (\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpreferences\u001b[39m\u001b[38;5;124m\"\u001b[39m, preferences),\n\u001b[1;32m     94\u001b[0m ]\n\u001b[1;32m     95\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m classical_execution_function \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_function.py:110\u001b[0m, in \u001b[0;36mQFunc._add_native_func_def\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    108\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfunc_decl\u001b[38;5;241m.\u001b[39mname \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_qmodule\u001b[38;5;241m.\u001b[39mnative_defs:\n\u001b[1;32m    109\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m\n\u001b[0;32m--> 110\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexpand\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    111\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_qmodule\u001b[38;5;241m.\u001b[39mnative_defs[\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfunc_decl\u001b[38;5;241m.\u001b[39mname] \u001b[38;5;241m=\u001b[39m NativeFunctionDefinition(\n\u001b[1;32m    112\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfunc_decl\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__dict__\u001b[39m, body\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbody\n\u001b[1;32m    113\u001b[0m )\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_expandable.py:85\u001b[0m, in \u001b[0;36mQExpandable.expand\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m     83\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mexpand\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m     84\u001b[0m     \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m:\n\u001b[0;32m---> 85\u001b[0m         \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_py_callable\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_get_positional_args\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n",
      "Cell \u001b[0;32mIn[25], line 18\u001b[0m, in \u001b[0;36mmain\u001b[0;34m(res)\u001b[0m\n\u001b[1;32m     16\u001b[0m prepare_int(\u001b[38;5;241m5\u001b[39m,y)\n\u001b[1;32m     17\u001b[0m prepare_int(\u001b[38;5;241m2\u001b[39m,z)\n\u001b[0;32m---> 18\u001b[0m \u001b[43mwithin_apply\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43;01mlambda\u001b[39;49;00m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mlinear_add_s1\u001b[49m\u001b[43m(\u001b[49m\u001b[43mx\u001b[49m\u001b[43m,\u001b[49m\u001b[43my\u001b[49m\u001b[43m,\u001b[49m\u001b[43mz\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mlambda\u001b[39;49;00m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mlinear_add_s1\u001b[49m\u001b[43m(\u001b[49m\u001b[43mz\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/builtins/operations.py:182\u001b[0m, in \u001b[0;36mwithin_apply\u001b[0;34m(compute, action)\u001b[0m\n\u001b[1;32m    177\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m QCallable\u001b[38;5;241m.\u001b[39mCURRENT_EXPANDABLE \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m    178\u001b[0m source_ref \u001b[38;5;241m=\u001b[39m get_source_ref(sys\u001b[38;5;241m.\u001b[39m_getframe(\u001b[38;5;241m1\u001b[39m))\n\u001b[1;32m    179\u001b[0m QCallable\u001b[38;5;241m.\u001b[39mCURRENT_EXPANDABLE\u001b[38;5;241m.\u001b[39mappend_statement_to_body(\n\u001b[1;32m    180\u001b[0m     WithinApply(\n\u001b[1;32m    181\u001b[0m         compute\u001b[38;5;241m=\u001b[39m_operand_to_body(compute),\n\u001b[0;32m--> 182\u001b[0m         action\u001b[38;5;241m=\u001b[39m\u001b[43m_operand_to_body\u001b[49m\u001b[43m(\u001b[49m\u001b[43maction\u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m    183\u001b[0m         source_ref\u001b[38;5;241m=\u001b[39msource_ref,\n\u001b[1;32m    184\u001b[0m     )\n\u001b[1;32m    185\u001b[0m )\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/builtins/operations.py:284\u001b[0m, in \u001b[0;36m_operand_to_body\u001b[0;34m(callable_)\u001b[0m\n\u001b[1;32m    283\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_operand_to_body\u001b[39m(callable_: Union[QCallable, Callable[[], \u001b[38;5;28;01mNone\u001b[39;00m]]) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m StatementBlock:\n\u001b[0;32m--> 284\u001b[0m     to_operand \u001b[38;5;241m=\u001b[39m \u001b[43mprepare_arg\u001b[49m\u001b[43m(\u001b[49m\u001b[43mQuantumOperandDeclaration\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcallable_\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    285\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(to_operand, \u001b[38;5;28mstr\u001b[39m):\n\u001b[1;32m    286\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m [QuantumFunctionCall(function\u001b[38;5;241m=\u001b[39mto_operand)]\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_expandable.py:229\u001b[0m, in \u001b[0;36mprepare_arg\u001b[0;34m(arg_decl, val)\u001b[0m\n\u001b[1;32m    226\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(val, QExpandable):\n\u001b[1;32m    227\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m val\u001b[38;5;241m.\u001b[39mfunc_decl\u001b[38;5;241m.\u001b[39mname\n\u001b[0;32m--> 229\u001b[0m \u001b[43mval\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexpand\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    230\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m QuantumLambdaFunction(\n\u001b[1;32m    231\u001b[0m     rename_params\u001b[38;5;241m=\u001b[39mval\u001b[38;5;241m.\u001b[39minfer_rename_params(), body\u001b[38;5;241m=\u001b[39mval\u001b[38;5;241m.\u001b[39mbody\n\u001b[1;32m    232\u001b[0m )\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_expandable.py:85\u001b[0m, in \u001b[0;36mQExpandable.expand\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m     83\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mexpand\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m     84\u001b[0m     \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mself\u001b[39m:\n\u001b[0;32m---> 85\u001b[0m         \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_py_callable\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_get_positional_args\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n",
      "Cell \u001b[0;32mIn[25], line 18\u001b[0m, in \u001b[0;36mmain.<locals>.<lambda>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     16\u001b[0m prepare_int(\u001b[38;5;241m5\u001b[39m,y)\n\u001b[1;32m     17\u001b[0m prepare_int(\u001b[38;5;241m2\u001b[39m,z)\n\u001b[0;32m---> 18\u001b[0m within_apply(\u001b[38;5;28;01mlambda\u001b[39;00m: linear_add_s1(x,y,z), \u001b[38;5;28;01mlambda\u001b[39;00m: \u001b[43mlinear_add_s1\u001b[49m\u001b[43m(\u001b[49m\u001b[43mz\u001b[49m\u001b[43m)\u001b[49m)\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_function.py:75\u001b[0m, in \u001b[0;36mQFunc.__call__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m     74\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__call__\u001b[39m(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;241m*\u001b[39margs: Any, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m---> 75\u001b[0m     \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__call__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     76\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_add_native_func_def()\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_callable.py:49\u001b[0m, in \u001b[0;36mQCallable.__call__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m     46\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m QCallable\u001b[38;5;241m.\u001b[39mCURRENT_EXPANDABLE \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m     47\u001b[0m source_ref \u001b[38;5;241m=\u001b[39m get_source_ref(sys\u001b[38;5;241m.\u001b[39m_getframe(\u001b[38;5;241m1\u001b[39m))\n\u001b[1;32m     48\u001b[0m QCallable\u001b[38;5;241m.\u001b[39mCURRENT_EXPANDABLE\u001b[38;5;241m.\u001b[39mappend_statement_to_body(\n\u001b[0;32m---> 49\u001b[0m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcreate_quantum_function_call\u001b[49m\u001b[43m(\u001b[49m\u001b[43msource_ref\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     50\u001b[0m )\n\u001b[1;32m     51\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_expandable.py:115\u001b[0m, in \u001b[0;36mQExpandable.create_quantum_function_call\u001b[0;34m(self, source_ref_, *args, **kwargs)\u001b[0m\n\u001b[1;32m    112\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mcreate_quantum_function_call\u001b[39m(\n\u001b[1;32m    113\u001b[0m     \u001b[38;5;28mself\u001b[39m, source_ref_: SourceReference, \u001b[38;5;241m*\u001b[39margs: Any, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any\n\u001b[1;32m    114\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m QuantumFunctionCall:\n\u001b[0;32m--> 115\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m_create_quantum_function_call\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    116\u001b[0m \u001b[43m        \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfunc_decl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msource_ref_\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\n\u001b[1;32m    117\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_expandable.py:291\u001b[0m, in \u001b[0;36m_create_quantum_function_call\u001b[0;34m(decl_, index_, source_ref_, *args, **kwargs)\u001b[0m\n\u001b[1;32m    289\u001b[0m arg_decls \u001b[38;5;241m=\u001b[39m decl_\u001b[38;5;241m.\u001b[39mget_positional_arg_decls()\n\u001b[1;32m    290\u001b[0m arg_list \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mlist\u001b[39m(args)\n\u001b[0;32m--> 291\u001b[0m prepared_args \u001b[38;5;241m=\u001b[39m \u001b[43m_prepare_args\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdecl_\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43marg_list\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    293\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m kwargs:\n\u001b[1;32m    294\u001b[0m     bad_kwarg \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mnext\u001b[39m(\u001b[38;5;28miter\u001b[39m(kwargs))\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_expandable.py:276\u001b[0m, in \u001b[0;36m_prepare_args\u001b[0;34m(decl, arg_list, kwargs)\u001b[0m\n\u001b[1;32m    274\u001b[0m         \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(arg_decl, QuantumOperandDeclaration):\n\u001b[1;32m    275\u001b[0m             error_message \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m _get_operand_hint(decl, arg_decl)\n\u001b[0;32m--> 276\u001b[0m         \u001b[38;5;28;01mraise\u001b[39;00m ClassiqValueError(error_message)\n\u001b[1;32m    277\u001b[0m     result\u001b[38;5;241m.\u001b[39mappend(prepare_arg(arg_decl, arg))\n\u001b[1;32m    279\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m result\n",
      "\u001b[0;31mClassiqValueError\u001b[0m: 'linear_add_s1' is missing required argument for 'y'\nIf you need further assistance, please reach out on our Community Slack channel at: https://short.classiq.io/join-slack\nIf the error persists feel free to open a ticket at: https://short.classiq.io/support"
     ]
    }
   ],
   "source": [
    "from classiq import *\n",
    "\n",
    "@qfunc\n",
    "def linear_add_s1(x:CInt, y:CInt, z:CInt) -> None:\n",
    "    temp = QNum(\"temp\")\n",
    "    res = QNum(\"res\")\n",
    "    temp |= x + y\n",
    "    res |= temp +z\n",
    "    \n",
    "@qfunc\n",
    "def main(res: Output[QNum]):\n",
    "    x = QNum(\"x\")\n",
    "    y = QNum(\"y\")\n",
    "    z = QNum(\"z\")\n",
    "    prepare_int(3,x)\n",
    "    prepare_int(5,y)\n",
    "    prepare_int(2,z)\n",
    "    within_apply(lambda: linear_add_s1(x,y,z), lambda: linear_add_s1(z))\n",
    "    #within\n",
    "\n",
    "qmod = create_model(main)\n",
    "qprog = synthesize(qmod)\n",
    "show(qprog)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Exercise 8b\n",
    "\n",
    "Why should we use `within-apply` and not just write three concatenated functions?\n",
    "To understand the motivation, we will create another arithmetic circuit.\n",
    "This time, however, we will also set Classiq’s synthesis engine to optimize on the circuit’s number of qubits, i.e., its width.\n",
    "\n",
    "Setting constraints can be done via the `set_constraints` operation - see [here](https://docs.classiq.io/latest/user-guide/platform/synthesis/constraints/).\n",
    "\n",
    "Perform the operation `res = w + x + y + z`, where w is initialized to 4 and the rest as before:\n",
    "\n",
    "1. Add `x` and `y` (as part of the `within_apply` operation)\n",
    "2. Add the result to `z` (as part of the within_apply operation)\n",
    "3. Uncompute the result of the first operation (as part of the `within_apply` operation)\n",
    "4. Add the result of the second operation to `w`. There’s no need to perform another uncomputation, as this brings our calculation to an end.\n",
    "\n",
    "Create the model, optimize on the circuit’s width, and run the circuit. Can you identify where qubits have been released and reused?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from classiq import *\n",
    "\n",
    "# Your code here:\n",
    "\n",
    "qmod = create_model(main)\n",
    "qprog = synthesize(qmod)\n",
    "show(qprog)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Bonus: Use a Single Arithmetic Expression\n",
    "\n",
    "What happens when we don't manually decompose this expression?\n",
    "\n",
    "Use Classiq’s arithmetic engine to calculate `res |= x + y + z + w` and optimize for width.\n",
    "Look at the resulting quantum program - can you identify the computation and uncomputation blocks? What else did you notice?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from classiq import *\n",
    "\n",
    "# Your code here:\n",
    "\n",
    "qmod = create_model(main)\n",
    "qprog = synthesize(qmod)\n",
    "show(qprog)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 9 - In-place Arithmetics\n",
    "\n",
    "For the following exercise we will use numeric quantum variables that represent fixed-point reals.\n",
    "\n",
    "Arithmetic expressions can be calculated in-place into a target variable, without allocating new qubits to store the result. This is done using the in-place-xor operator.\n",
    "\n",
    "See also [Numeric assignment](https://docs.classiq.io/latest/user-guide/platform/qmod/language-reference/statements/numeric-assignment/#semantics).\n",
    "\n",
    "In-place assignment is often used to nest arithmetic expressions under quantum operators. Note that out-of-place assignment requires its left-value variable to be un-initialized, and therefore cannot be used under an operator if the variable is declared outside its scope. Applying operators to arithmetic expressions is required in many algorithms. One example is the piecewise evaluation of mathematical functions - calculating different expressions over `x` depending on the subdomain where `x` falls.\n",
    "\n",
    "For this exercise, replace the missing parts in the code snippet below to evaluate the result of:\n",
    "\n",
    "$$\n",
    "f(x) = \\begin{cases}\n",
    "      2x + 1 & \\text{ if } 0 \\leq x < 0.5 \\\\\n",
    "      x + 0.5 & \\text{ if } 0.5 \\leq x < 1\n",
    "   \\end{cases}\n",
    "$$\n",
    "\n",
    "Notes:\n",
    "- We cannot use `x` directly as the control variable in a `constrol` operator, because it also occurs in the nested scope. to determine if `x` is in the lower or higher half of the domain we duplicate the most significant bit onto a separate variable called `label`.\n",
    "- In Python assignment operators cannot be used in lambda expressions, so the computation of the function needs to be factored out to a named Python function (but not necessarily a Qmod function).\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "object of type 'int' has no len()",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[26], line 28\u001b[0m\n\u001b[1;32m     24\u001b[0m     X(label)\n\u001b[1;32m     25\u001b[0m     control(label, \u001b[38;5;28;01mlambda\u001b[39;00m: linear_func(\u001b[38;5;241m2.0\u001b[39m, \u001b[38;5;241m1.0\u001b[39m, x, res))  \u001b[38;5;66;03m# 0.0 <= x < 0.5\u001b[39;00m\n\u001b[0;32m---> 28\u001b[0m qmod \u001b[38;5;241m=\u001b[39m \u001b[43mcreate_model\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmain\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     29\u001b[0m qprog \u001b[38;5;241m=\u001b[39m synthesize(qmod)\n\u001b[1;32m     30\u001b[0m show(qprog)\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_function.py:40\u001b[0m, in \u001b[0;36mcreate_model\u001b[0;34m(entry_point, constraints, execution_preferences, preferences, classical_execution_function)\u001b[0m\n\u001b[1;32m     33\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mcreate_model\u001b[39m(\n\u001b[1;32m     34\u001b[0m     entry_point: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mQFunc\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m     35\u001b[0m     constraints: Optional[Constraints] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m     38\u001b[0m     classical_execution_function: Optional[CFunc] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m     39\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m SerializedModel:\n\u001b[0;32m---> 40\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[43mentry_point\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfunc_decl\u001b[49m\u001b[38;5;241m.\u001b[39mname \u001b[38;5;241m!=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmain\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m     41\u001b[0m         \u001b[38;5;28;01mraise\u001b[39;00m ClassiqError(\n\u001b[1;32m     42\u001b[0m             \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThe entry point function must be named \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmain\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, got \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mentry_point\u001b[38;5;241m.\u001b[39mfunc_decl\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m     43\u001b[0m         )\n\u001b[1;32m     44\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m entry_point\u001b[38;5;241m.\u001b[39mcreate_model(\n\u001b[1;32m     45\u001b[0m         constraints, execution_preferences, preferences, classical_execution_function\n\u001b[1;32m     46\u001b[0m     )\u001b[38;5;241m.\u001b[39mget_model()\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/quantum_function.py:71\u001b[0m, in \u001b[0;36mQFunc.func_decl\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m     67\u001b[0m \u001b[38;5;129m@property\u001b[39m\n\u001b[1;32m     68\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mfunc_decl\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m QuantumFunctionDeclaration:\n\u001b[1;32m     69\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_qmodule\u001b[38;5;241m.\u001b[39mnative_defs\u001b[38;5;241m.\u001b[39mget(\n\u001b[1;32m     70\u001b[0m         \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_py_callable\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__name__\u001b[39m,\n\u001b[0;32m---> 71\u001b[0m         \u001b[43minfer_func_decl\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_py_callable\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mqmodule\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_qmodule\u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m     72\u001b[0m     )\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/declaration_inferrer.py:160\u001b[0m, in \u001b[0;36minfer_func_decl\u001b[0;34m(py_func, qmodule)\u001b[0m\n\u001b[1;32m    155\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minfer_func_decl\u001b[39m(\n\u001b[1;32m    156\u001b[0m     py_func: Callable, qmodule: ModelStateContainer\n\u001b[1;32m    157\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m QuantumFunctionDeclaration:\n\u001b[1;32m    158\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m QuantumFunctionDeclaration(\n\u001b[1;32m    159\u001b[0m         name\u001b[38;5;241m=\u001b[39munmangle_keyword(py_func\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__name__\u001b[39m),\n\u001b[0;32m--> 160\u001b[0m         positional_arg_declarations\u001b[38;5;241m=\u001b[39m\u001b[43m_extract_positional_args\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    161\u001b[0m \u001b[43m            \u001b[49m\u001b[43mpy_func\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;18;43m__annotations__\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mqmodule\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mqmodule\u001b[49m\n\u001b[1;32m    162\u001b[0m \u001b[43m        \u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m    163\u001b[0m     )\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/declaration_inferrer.py:146\u001b[0m, in \u001b[0;36m_extract_positional_args\u001b[0;34m(args, qmodule)\u001b[0m\n\u001b[1;32m    144\u001b[0m     result\u001b[38;5;241m.\u001b[39mappend(_extract_param_decl(name, py_type, qmodule\u001b[38;5;241m=\u001b[39mqmodule))\n\u001b[1;32m    145\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m QVar\u001b[38;5;241m.\u001b[39mfrom_type_hint(py_type) \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m--> 146\u001b[0m     result\u001b[38;5;241m.\u001b[39mappend(\u001b[43m_extract_port_decl\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpy_type\u001b[49m\u001b[43m)\u001b[49m)\n\u001b[1;32m    147\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m    148\u001b[0m     \u001b[38;5;28;01massert\u001b[39;00m (get_origin(py_type) \u001b[38;5;129;01mor\u001b[39;00m py_type) \u001b[38;5;129;01mis\u001b[39;00m QCallable \u001b[38;5;129;01mor\u001b[39;00m (\n\u001b[1;32m    149\u001b[0m         get_origin(py_type) \u001b[38;5;129;01mor\u001b[39;00m py_type\n\u001b[1;32m    150\u001b[0m     ) \u001b[38;5;129;01mis\u001b[39;00m QCallableList\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/declaration_inferrer.py:111\u001b[0m, in \u001b[0;36m_extract_port_decl\u001b[0;34m(name, py_type)\u001b[0m\n\u001b[1;32m    106\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(py_type, _AnnotatedAlias):\n\u001b[1;32m    107\u001b[0m     py_type \u001b[38;5;241m=\u001b[39m py_type\u001b[38;5;241m.\u001b[39m__args__[\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m    108\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m PortDeclaration(\n\u001b[1;32m    109\u001b[0m     name\u001b[38;5;241m=\u001b[39mname,\n\u001b[1;32m    110\u001b[0m     direction\u001b[38;5;241m=\u001b[39mdirection,\n\u001b[0;32m--> 111\u001b[0m     quantum_type\u001b[38;5;241m=\u001b[39m\u001b[43mqtype\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto_qmod_quantum_type\u001b[49m\u001b[43m(\u001b[49m\u001b[43mpy_type\u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m    112\u001b[0m )\n",
      "File \u001b[0;32m~/opt/anaconda3/envs/Classiq/lib/python3.9/site-packages/classiq/qmod/qmod_variable.py:256\u001b[0m, in \u001b[0;36mQNum.to_qmod_quantum_type\u001b[0;34m(cls, type_hint)\u001b[0m\n\u001b[1;32m    254\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mcls\u001b[39m\u001b[38;5;241m.\u001b[39mQMOD_TYPE()\n\u001b[1;32m    255\u001b[0m type_args \u001b[38;5;241m=\u001b[39m type_args[\u001b[38;5;241m0\u001b[39m]\n\u001b[0;32m--> 256\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28;43mlen\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mtype_args\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;241m!=\u001b[39m \u001b[38;5;241m3\u001b[39m:\n\u001b[1;32m    257\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m ClassiqValueError(\n\u001b[1;32m    258\u001b[0m         \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mQNum receives three type arguments: QNum[size: int | CInt, \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m    259\u001b[0m         \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mis_signed: bool | CBool, fraction_digits: int | CInt]\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m    260\u001b[0m     )\n\u001b[1;32m    261\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mcls\u001b[39m\u001b[38;5;241m.\u001b[39mQMOD_TYPE(\n\u001b[1;32m    262\u001b[0m     size\u001b[38;5;241m=\u001b[39mExpression(expr\u001b[38;5;241m=\u001b[39mget_type_hint_expr(type_args[\u001b[38;5;241m0\u001b[39m])),\n\u001b[1;32m    263\u001b[0m     is_signed\u001b[38;5;241m=\u001b[39mExpression(expr\u001b[38;5;241m=\u001b[39mget_type_hint_expr(type_args[\u001b[38;5;241m1\u001b[39m])),\n\u001b[1;32m    264\u001b[0m     fraction_digits\u001b[38;5;241m=\u001b[39mExpression(expr\u001b[38;5;241m=\u001b[39mget_type_hint_expr(type_args[\u001b[38;5;241m2\u001b[39m])),\n\u001b[1;32m    265\u001b[0m )\n",
      "\u001b[0;31mTypeError\u001b[0m: object of type 'int' has no len()"
     ]
    }
   ],
   "source": [
    "\n",
    "from classiq import *\n",
    "\n",
    "\n",
    "def linear_func(a: float, b: float, x: QNum, res: QNum) -> None:\n",
    "    res ^= a * x + b\n",
    "\n",
    "\n",
    "@qfunc\n",
    "def dup_msb(qba: QArray[QBit], msb: QBit) -> None:\n",
    "    CX(qba[qba.len - 1], msb)\n",
    "\n",
    "\n",
    "@qfunc\n",
    "def main(x: Output[QNum[3, False, 3]], res: Output[QNum[5, False, 3]]) -> None:\n",
    "    allocate(5, res)\n",
    "    allocate(3, x)\n",
    "    hadamard_transform(x)\n",
    "\n",
    "    label = QArray(\"label\")\n",
    "    allocate(1, label)\n",
    "\n",
    "    dup_msb(x, label)\n",
    "    control(label, lambda: linear_func(1.0, 0.5, x, res))  # 0.5 <= x < 1.0\n",
    "    X(label)\n",
    "    control(label, lambda: linear_func(2.0, 1.0, x, res))  # 0.0 <= x < 0.5\n",
    "\n",
    "\n",
    "qmod = create_model(main)\n",
    "qprog = synthesize(qmod)\n",
    "show(qprog)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 10 - State-preparation Algorithm using Quantum-if\n",
    "\n",
    "#### Binding\n",
    "The `bind` operation allows to convert smoothly between different quantum types and split or slice bits when necessary. Here’s an example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Opening: https://platform.classiq.io/circuit/303cab63-53d9-4088-ab6c-63ca4022558d?version=0.40.0\n"
     ]
    }
   ],
   "source": [
    "from classiq import *\n",
    "\n",
    "\n",
    "\n",
    "from classiq import *\n",
    "from math import pi\n",
    "\n",
    "\n",
    "@qfunc\n",
    "def main(res: Output[QArray[QBit]]) -> None:\n",
    "    x: QArray[QBit] = QArray(\"x\")\n",
    "    allocate(3, x)\n",
    "    hadamard_transform(x)\n",
    "\n",
    "    lsb = QBit(\"lsb\")\n",
    "    msb = QNum(\"msb\", 2, False, 0)\n",
    "    bind(x, [lsb, msb])\n",
    "\n",
    "    control(msb == 1, lambda: RY(pi / 3, lsb))   # msb==1 <==> bit1 bit2 == 01 (binary of decimal 1)\n",
    "\n",
    "    bind([lsb, msb], res)\n",
    "\n",
    "model = create_model(main)\n",
    "qprog = synthesize(model)\n",
    "show(qprog)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The first `bind` operation splits the 3-qubit register `x` into the 2-qubit and single-qubit registers `lsb` and `msb`, respectively.\n",
    "\n",
    "After the `bind` operation:\n",
    "1. The registers `lsb` and `msb` can be operated on as separated registers.\n",
    "2. The register`x` is consumed and can no longer be used.\n",
    "\n",
    "The second `bind` operation concatenates the registers to the output register `res`.\n",
    "\n",
    "For this exercise, fill in the missing code parts in the above snippet and use the `control` statement to manually generate the following lovely 3-qubit probability distribution: `[1/8, 1/8, 1/8, -sqrt(3)/16, 1/8 + sqrt(3)/16, 1/8, 1/8, 1/8, 1/8]`.\n",
    "\n",
    "The following series of gates generate it:\n",
    "\n",
    "Perform the Hadamard transform on all three qubits.\n",
    "\n",
    "Apply a rotation on the LSB (least-significant bit) conditioned by the MSB being |0> and the second to last MSB being |1>. How would you write this condition using a QNum?\n",
    "\n",
    "The following series of gates generate it:\n",
    "1. Perform the Hadamard transform on all three qubits.\n",
    "2. Apply a `pi/3` rotation on the LSB (least-significant bit) conditioned by the MSB being |0> and the second to last MSB being |1>. How would you write this condition using a QNum?\n",
    "\n",
    "If you want to validate your results without looking at the full solution, compare them to running using Classiq’s built-in `prepare_state` function.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from classiq import *\n",
    "from classiq.qmod.symbolic import sqrt\n",
    "\n",
    "prob_list= [\n",
    "            1 / 8,\n",
    "            1 / 8,\n",
    "            1 / 8,\n",
    "            -sqrt(3) / 16,\n",
    "            1 / 8 + sqrt(3) / 16,\n",
    "            1 / 8,\n",
    "            1 / 8,\n",
    "            1 / 8,\n",
    "            1 / 8,\n",
    "        ]\n",
    "@qfunc\n",
    "def pre_prepared_state(q: QArray[QBit]) -> None:\n",
    "    prepare_state(\n",
    "        [\n",
    "            1 / 8,\n",
    "            1 / 8,\n",
    "            1 / 8,\n",
    "            -sqrt(3) / 16,\n",
    "            1 / 8 + sqrt(3) / 16,\n",
    "            1 / 8,\n",
    "            1 / 8,\n",
    "            1 / 8,\n",
    "            1 / 8,\n",
    "        ],\n",
    "        0.0,\n",
    "        q,\n",
    "    )\n",
    "\n",
    "\n",
    "# Your code here:"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
